package com.example.demo.base.stream;

import org.junit.Test;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @program: java_base
 * @description: streamDemo
 * @author: zhouhongtao
 * @happyCreateTime: 2022/01/24 15:16
 * @Link address : https://mp.weixin.qq.com/s?__biz=MzkwOTAyMTY2NA==&mid=2247486429&idx=1&sn=bf4a8ea11509cd9504f08cc1bec964d2&chksm=c0c05352f7b7da44f2649e4f6189f4ac07dcfbd6d0ffc6df0fef2d887fd6a38e72b64a09fe96&mpshare=1&scene=24&srcid=1130dLkyxw859CiDVkSiyiW7&sharer_sharetime=1638233400760&sharer_shareid=31b45ee6fbbeef3f5aeeef442014ffcd&exportkey=A8mln4yRJ4gjjuhLnsLcXmA%3D&acctmode=0&pass_ticket=VEEbeiVXv05W5n%2FwaQ1U359%2BCZDEknrhUbacDbRf9y3SPcOSPkMLuF%2FhiB%2FeUtO%2F&wx_header=0#rd
 *
 */
public class StreamDemo {


    /**
     * Stream :
     *  1.Stream特性
     *  2.Stream创建
     *  3.Stream源码
     * Stream 使用：
     * ------- 以下为终端操作 ----------
     *  1.遍历 foreach
     *  2.匹配：find match
     *  3.规约：reduce
     *  4.聚合：max min count
     *  5.收集：collect
     *      5.1 统计：summarizing counting averaging
     *      5.2 分组：groupingBy partitioningBy
     *      5.3 接合：joining
     *      5.4 归约：reduce
     *      5.5 归集 toList toSet toMap
     *
     * --------- 以下为中间操作 -------
     *  6.筛选：filter
     *  7.映射：map
     *  8.排序：sorted
     *  9.提取与组合
     */

    /**
     * Stream有几个特性：
     * 1.stream 不存储数据，而是按照特定的规则对数据进行计算，一般会输出结果。
     * 2.stream 不会改变数据源，通常情况下会产生一个新的集合或一个值。
     * 3.stream 具有延迟执行特性，只有调用终端操作时，中间操作才会执行。
     */

    // TODO reducing？不懂
    // TODO or todo reduce 不懂
    /***
     * 题目：
     * 1.从员工集合中筛选出 salary 大于 8000 的员工，并放置到新的集合里。
     * 2.统计员工的最高薪资、平均薪资、薪资之和。
     * 3.将员工按薪资从高到低排序，同样薪资者年龄小者在前。
     * 4.将员工按性别分类，将员工按性别和地区分类，将员工按薪资是否高于 8000 分为两部分。
     */
    @Test
    public void test1(){
        // stream 创建：java.util.Collection.stream() 方法用集合创建流
        List<String> strings = Arrays.asList("", "", "", "", "");
        // 顺序 Stream
        Stream<String> stream = strings.stream();
        // 并行 Stream
        Stream<String> stringStream = strings.parallelStream();


        // java.util.Arrays.stream(T[] array)方法用数组创建流
        IntStream stream1 = Arrays.stream(new int[]{1, 4, 3, 4, 45});

        // Stream的静态方法：of()、iterate()、generate()
        Stream<Integer> integerStream = Stream.of(1, 2, 32, 4);
        Stream<Integer> stream2 = Stream.iterate(1, (x) -> x + 3).limit(4);
        stream2.forEach(System.out::println);
        Stream<Double> stream3 = Stream.generate(Math::random).limit(4);
        stream3.forEach(System.out::println);

    }

    /**
     * stream和parallelStream的简单区分：
     *  stream是顺序流，由主线程按顺序对流执行操作，
     *  而parallelStream是并行流，内部以多线程并行执行的方式对流进行操作，
     *  但前提是流中的数据处理没有顺序要求。例如筛选集合中的奇数，两者的处理不同之处：
     *  如果流中的数据量足够大，并行流可以加快处速度。
     *
     *  除了直接创建并行流，还可以通过parallel()把顺序流转换成并行流：
     */
    @Test
    public void test2() {
        List<Integer> list = Arrays.asList(1, 2,12312,123355,456,456345,6567,85567858,5678,5678781, 3, 45, 6,7);
        Optional<Integer> findFirst = list.stream().parallel().filter(x -> x > 6).findFirst();
        findFirst.stream().forEach(System.out::println);
    }

    /**
     * Optional类是一个可以为null的容器对象。
     * 如果值存在则isPresent()方法会返回true，调用get()方法会返回该对象。
     * 更详细说明请见：Java 8 Optional 类详解
     * http://itsoku.com/article/200
     * 遍历/匹配 findFirst  findAny   matchAny   foreach
     */
    @Test
    public void test3_2() {
        // Stream也是支持类似集合的遍历和匹配元素的，只是Stream中的元素是以Optional类型存在的。
        List<Integer> list = Arrays.asList(2, 3, 4, 34, 45, 456, 567, 5);
        list.stream().filter(x -> x > 6).forEach(System.out::println);

        Optional<Integer> findFirst = list.stream().filter(x -> x > 6).findFirst();
        Optional<Integer> findAny = list.parallelStream().filter(x -> x > 6).findAny();
        boolean anyMatch = list.stream().anyMatch(x -> x > 6);
        System.out.println("匹配第一个值"+findFirst.get());
        System.out.println("匹配任意一个值"+findAny.get());
        System.out.println("是否存在大于6的值"+anyMatch);
    }


    /**
     * 筛选(filter)：按照一定的规则校验流中的元素，将符合条件的元素提取到新的流中的操作
     *
     */
    @Test
    public void test3_3() {
        List<Integer> list = Arrays.asList(6, 7, 3, 8, 1, 2, 9);
        list.stream()
                .filter(x -> x > 7)
                .forEach(System.out::println);

        /**
         * demo2
         * 筛选员工中工资高于 8000 的人，并形成新的集合。
         * 形成新集合依赖collect（收集），后文有详细介绍。
         *
         */
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
        personList.add(new Person("Anni", 8200, 24, "female", "New York"));
        personList.add(new Person("Owen", 9500, 25, "male", "New York"));
        personList.add(new Person("Alisa", 7900, 26, "female", "New York"));

        personList.stream()
                .filter(x -> x.getSalary() > 8000)
                .collect(Collectors.toList())
                .forEach(System.out::println);

        List<String> filterList = personList.stream()
                .filter(x -> x.getSalary() > 8000)
                .map(Person::getName)
                .collect(Collectors.toList());

        System.out.print("高于8000的员工姓名：" + filterList);
    }

    /**
     * 聚合：max、min、count这些字眼你一定不陌生，
     * 在 mysql 中我们常用它们进行数据统计。
     * Java stream 中也引入了这些概念和用法，
     * 极大地方便了我们对集合、数组的数据统计工作。
     */
    @Test
    public void test3_4() {
        // demo_1 获取String集合中最长的元素
        List<String> list_1 = Arrays.asList("adnm", "admmt", "pot", "xbangd", "weoujgsd");
        Optional<String> max = list_1.stream().max(Comparator.comparing(String::length));
        System.out.println("max length is "+ max.get());

        // demo_2 获取Integer集合中的最大值
        List<Integer> list_2 = Arrays.asList(7, 6, 9, 4, 11, 6);
        Optional<Integer> max1 = list_2.stream().max(Integer::compareTo);

        Optional<Integer> max2 = list_2.stream().max(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        });

        System.out.println("max1 :"+ max1.get());
        System.out.println("max2 :"+ max2.get());


        // demo_3 获取员工工资最高的人
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
        personList.add(new Person("Anni", 8200, 24, "female", "New York"));
        personList.add(new Person("Owen", 9500, 25, "male", "New York"));
        personList.add(new Person("Alisa", 7900, 26, "female", "New York"));

        Optional<Person> max3 = personList.stream().max(Comparator.comparingInt(Person::getSalary));
        System.out.println(max3.get().getName());


        // demo_4 计算Integer集合中大于 6 的元素的个数
        List<Integer> list = Arrays.asList(7, 6, 4, 8, 2, 11, 9);
        long count = list.stream().filter(x -> x > 6).count();
        System.out.println("> 6 count : " + count);
    }

    /**
     * 映射(map/flatMap)：映射，可以将一个流的元素按照一定的映射规则映射到另一个流中。分为map和flatMap：
     * map：接收一个函数作为参数，该函数会被应用到每个元素上，并将其映射成一个新的元素。
     * flatMap：接收一个函数作为参数，将流中的每个值都换成另一个流，然后把所有流连接成一个流。
     */
    @Test
    public void test3_5() {
        // demo_1 英文字符串数组的元素全部改为大写。
        String[] strArr = { "abcd", "bcdd", "defde", "fTr" };
        List<String> strList  = Arrays.stream(strArr).map(String::toUpperCase).collect(Collectors.toList());
        // 整数数组每个元素+3
        List<Integer> intList = Arrays.asList(1, 3, 5, 7, 9, 11);
        List<Integer> intListNew  = intList.stream().map(x -> x + 3).collect(Collectors.toList());
        System.out.println("每个元素大写：" + strList);
        System.out.println("每个元素+3：" + intListNew);


        // demo_2 将员工的薪资全部增加 1000。
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
        personList.add(new Person("Anni", 8200, 24, "female", "New York"));
        personList.add(new Person("Owen", 9500, 25, "male", "New York"));
        personList.add(new Person("Alisa", 7900, 26, "female", "New York"));

        // 不改变原来员工集合的方式
        List<Person> personListNew = personList.stream().map(person -> {
            Person personNew = new Person(person.getName(), 0, 0, null, null);
            personNew.setSalary(person.getSalary() + 1000);
            return personNew;
        }).collect(Collectors.toList());

        System.out.println("一次改动前：" + personList.get(0).getName() + "-->" + personList.get(0).getSalary());
        System.out.println("一次改动后：" + personListNew.get(0).getName() + "-->" + personListNew.get(0).getSalary());

        // 改变原来员工集合的方式
        List<Person> personListNew2 =  personList.stream()
                .map(person -> {
                    person.setSalary(person.getSalary() + 1000);
                    return person;
                })
                .collect(Collectors.toList());
        System.out.println("二次改动前：" + personList.get(0).getName() + "-->" + personListNew.get(0).getSalary());
        System.out.println("二次改动后：" + personListNew2.get(0).getName() + "-->" + personListNew.get(0).getSalary());


        // demo_3 将两个字符数组合并成一个新的字符数组。
        List<String> list = Arrays.asList("m,k,l,a", "1,3,5,7");
        List<String> listNew  = list.stream()
                .flatMap(s -> {
                    String[] split = s.split(",");
                    Stream<String> stream = Arrays.stream(split);
                    return stream;
                })
                .collect(Collectors.toList());

        System.out.println("处理前的集合：" + list);
        System.out.println("处理后的集合：" + listNew);
    }

    /**
     * 归约(reduce): 归约，也称缩减，顾名思义，是把一个流缩减成一个值，能实现对集合求和、求乘积和求最值操作。
     * reduce：还存有疑问，特别是：reduce（，，） 此函数
     */
    @Test
    public void test3_6(){
        // demo_1 Integer集合的元素之和、乘积和最大值。
        List<Integer> list = Arrays.asList(1, 3, 2, 8, 11, 4);
        // 求和方式1
        Optional<Integer> sum = list.stream().reduce((x, y) -> x + y);
        // 求和方式2
        Optional<Integer> sum2 = list.stream().reduce(Integer::sum);
        // 求和方式3
        Integer sum3 = list.stream().reduce(0, Integer::sum);
        // 求乘积
        Optional<Integer> product  = list.stream().reduce((x, y) -> x * y);
        // 求最大值方式1
        Optional<Integer> max = list.stream().reduce((x, y) -> x > y ? x : y);
        // 求最大值写法2
        Integer max2 = list.stream().reduce(1, Integer::max);
        System.out.println("list求和：" + sum.get() + "," + sum2.get() + "," + sum3);
        System.out.println("list求积：" + product.get());
        System.out.println("list求和：" + max.get() + "," + max2);

        // demo_2 求所有员工的工资之和和最高工资
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
        personList.add(new Person("Anni", 8200, 24, "female", "New York"));
        personList.add(new Person("Owen", 9500, 25, "male", "New York"));
        personList.add(new Person("Alisa", 7900, 26, "female", "New York"));

        // 求工资之和方式1：
        Optional<Integer> sumSalary  = personList.stream().map(Person::getSalary).reduce((x, y) -> x + y);
        // 求工资之和方式2：
        Integer sumSalary2 = personList.stream()
                .reduce(0
                        ,(sum_1, p) -> sum_1 += p.getSalary()
                        ,(sum1_1, sum_2) -> sum1_1 + sum_2);
        // 求工资之和方式3：
        Integer sumSalary3 = personList.stream()
                .reduce(0
                        , (sum3_1, p) -> sum3_1 += p.getSalary()
                        , Integer::sum);

        // 求最高工资方式1：
        Integer maxSalary = personList.stream()
                .reduce(0
                        , (max_1, p) -> max_1 > p.getSalary() ? max_1 : p.getSalary()
                        ,Integer::max);

        // 求最高工资方式2：
        Integer maxSalary2 = personList.stream()
                .reduce(0
                        , (max_3, p) -> max_3 > p.getSalary() ? max_3 : p.getSalary()
                        , (max1_, max2_) -> max1_ > max2_ ? max1_ : max2_);

        System.out.println("工资之和：" + sumSalary.get() + "," + sumSalary2 + "," + sumSalary3);
        System.out.println("最高工资：" + maxSalary + "," + maxSalary2);
    }

    /**
     *  收集(collect): 收集，可以说是内容最繁多、功能最丰富的部分了。
     *  从字面上去理解，就是把一个流收集起来，最终可以是收集成一个值也可以收集成一个新的集合。
     *  collect 主要依赖java.util.stream.Collectors 类内置的静态方法
     *
     *  归集(toList/toSet/toMap):
     *  因为流不存储数据，那么在流中的数据完成处理后，需要将流中的数据重新归集到新的集合里。
     *  toList、toSet和toMap比较常用，另外还有toCollection、toConcurrentMap等复杂一些的用法。
     */
    @Test
    public void test3_7_1(){
        List<Integer> list = Arrays.asList(1, 6, 3, 4, 6, 7, 9, 6, 20);
        List<Integer> listNew = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
        Set<Integer> set = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toSet());

        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
        personList.add(new Person("Anni", 8200, 24, "female", "New York"));

        Map<?, Person> map = personList.stream()
                .filter(p -> p.getSalary() > 8000)
                .collect(
                        Collectors.toMap(Person::getName, p -> p));
        System.out.println("toList:" + listNew);
        System.out.println("toSet:" + set);
        System.out.println("toMap:" + map);
    }


    /**
     * 统计(count/averaging)：
     * Collectors提供了一系列用于数据统计的静态方法：
     *
     * 计数：count
     * 平均值：averagingInt、averagingLong、averagingDouble
     * 最值：maxBy、minBy
     * 求和：summingInt、summingLong、summingDouble
     * 统计以上所有：summarizingInt、summarizingLong、summarizingDouble
     */
    @Test
    public void test3_7_2(){
        // demo_1 统计员工人数、平均工资、工资总额、最高工资
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));

        // 求总数
        Long count  = personList.stream()
                .collect(Collectors.counting());
        // 求平均工资
        Double average  = personList.stream()
                .collect(
                        Collectors.averagingDouble(Person::getSalary));
        // 求最高工资
        Optional<Integer> max = personList.stream().map(Person::getSalary)
                .collect(
                        Collectors.maxBy(Integer::compare));
        // 求工资之和
        Integer sum  = personList.stream()
                .collect(
                        Collectors.summingInt(Person::getSalary));
        System.out.println(sum );
        // 一次性统计所有信息
        DoubleSummaryStatistics collect = personList.stream()
                .collect(
                        Collectors.summarizingDouble(Person::getSalary));

        System.out.println("员工总数：" + count);
        System.out.println("员工平均工资：" + average);
        System.out.println("员工工资总和：" + sum);
        System.out.println("员工工资所有统计：" + collect);
    }


    /**
     * 分组(partitioningBy/groupingBy)
     * 分区：将stream按条件分为两个Map，比如员工按薪资是否高于 8000 分为两部分。
     * 分组：将集合分为多个 Map，比如员工按性别分组。有单级分组和多级分组。
     */
    @Test
    public void test3_7_3(){
        // 将员工按薪资是否高于 8000 分为两部分；将员工按性别和地区分组
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, "male", "New York"));
        personList.add(new Person("Jack", 7000, "male", "Washington"));
        personList.add(new Person("Lily", 7800, "female", "Washington"));
        personList.add(new Person("Anni", 8200, "female", "New York"));
        personList.add(new Person("Owen", 9500, "male", "New York"));
        personList.add(new Person("Alisa", 7900, "female", "New York"));

        // 将员工按薪资是否高于8000分组
        Map<Boolean, List<Person>> part  = personList.stream()
                .collect(
                        Collectors
                                .partitioningBy(x -> x.getSalary() > 8000)
                );
        // 将员工按性别分组
        Map<String, List<Person>> group  = personList.stream()
                .collect(
                        Collectors.groupingBy(Person::getSex)
                );

        // 将员工先按性别分组，再按地区分组
        Map<String, Map<String, List<Person>>> group2 = personList.stream()
                .collect(
                        Collectors.groupingBy(
                                Person::getSex
                                , Collectors.groupingBy(Person::getArea)));

        System.out.println("员工按薪资是否大于8000分组情况：" + part);
        System.out.println("员工按性别分组情况：" + group);
        System.out.println("员工按性别、地区：" + group2);
    }

    /**
     * 接合(joining):
     * joining可以将 stream 中的元素用特定的连接符（没有的话，则直接连接）连接成一个字符串。
     */
    @Test
    public void test3_7_4(){
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));

        // 所有员工的姓名
        String names = personList.stream().map(Person::getName).collect(Collectors.joining(","));
//        String names = personList.stream().map(p -> p.getName()).collect(Collectors.joining(","));
        System.out.println("所有员工的姓名：" + names);
        List<String> list = Arrays.asList("A", "B", "C");
        String string = list.stream().collect(Collectors.joining("-"));
        System.out.println("拼接后的字符串：" + string);
    }


    /**
     *  归约(reducing):
     *  Collectors类提供的reducing方法，
     *  相比于stream本身的reduce方法，增加了对自定义归约的支持。
     *
     */
    @Test
    public void test3_7_5(){
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));

        // 每个员工减去起征点后的薪资之和（这个例子并不严谨，但一时没想到好的例子）
        Integer sum = personList.stream().collect(
                Collectors.reducing(0
                        , Person::getSalary
                        , (i, j) -> (i + j - 5000)));
        System.out.println("员工扣税薪资总和：" + sum);

        // stream的reduce
        Optional<Integer> sum2 = personList.stream().map(Person::getSalary).reduce(Integer::sum);
        System.out.println("员工薪资总和：" + sum2.get());
    }


    /**
     * 排序(sorted)：
     * sorted，中间操作。有两种排序：
     *  sorted()：自然排序，流中元素需实现 Comparable 接口
     *  sorted(Comparator com)：Comparator 排序器自定义排序
     */
    @Test
    public void test3_8(){
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Sherry", 9000, 24, "female", "New York"));
        personList.add(new Person("Tom", 8900, 22, "male", "Washington"));
        personList.add(new Person("Jack", 9000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 8800, 26, "male", "New York"));
        personList.add(new Person("Alisa", 9000, 26, "female", "New York"));

        // 将员工按工资由高到低（工资一样则按年龄由大到小）排序
//        Stream<Integer> sorted = personList.stream().map(Person::getSalary).sorted();
        // 按工资升序排序（自然排序）
        List<String> newList = personList.stream()
                .sorted(Comparator.comparing(Person::getSalary))
                .map(Person::getName)
                .collect(Collectors.toList());

        // 按工资倒序排序
//        Stream<Person> sorted1 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed());
        List<String> newList2 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed())
                .map(Person::getName).collect(Collectors.toList());

        // 先按工资再按年龄升序排序
        List<String> newList3 = personList.stream()
                .sorted(Comparator.comparing(Person::getSalary).thenComparing(Person::getAge)).map(Person::getName)
                .collect(Collectors.toList());

        // 先按工资再按年龄自定义排序（降序）
        List<String> newList4 = personList.stream().sorted((p1, p2) -> {
            if (p1.getSalary() == p2.getSalary()) {
                return p2.getAge() - p1.getAge();
            } else {
                return p2.getSalary() - p1.getSalary();
            }
        }).map(Person::getName).collect(Collectors.toList());

        System.out.println("按工资升序排序：" + newList);
        System.out.println("按工资降序排序：" + newList2);
        System.out.println("先按工资再按年龄升序排序：" + newList3);
        System.out.println("先按工资再按年龄自定义降序排序：" + newList4);
    }


    /**
     * 提取/组合:
     * 流也可以进行合并、去重、限制、跳过等操作。
     */
    @Test
    public void test3_9(){
        String[] arr1 = { "a", "b", "c", "d" };
        String[] arr2 = { "d", "e", "f", "g" };

        Stream<String> stream1 = Stream.of(arr1);
        Stream<String> stream2 = Stream.of(arr2);
        // concat:合并两个流 distinct：去重
        List<String> newList  = Stream.concat(stream1, stream2)
                .distinct()
                .collect(Collectors.toList());

        // limit：限制从流中获得前n个数据
        List<Integer> collect = Stream
                .iterate(1, x -> x + 2)
                .limit(10)
                .collect(Collectors.toList());
        // skip：跳过前n个数据
        List<Integer> collect2 = Stream
                .iterate(1, x -> x + 2)
                .skip(1)
                .limit(5)
                .collect(Collectors.toList());

        System.out.println("流合并：" + newList);
        System.out.println("limit：" + collect);
        System.out.println("skip：" + collect2);


        // limit：限制从流中获得前n个数据
        List<Integer> collect3 = Stream
                .iterate(5, x -> x + 3).limit(3).collect(Collectors.toList());
        collect3.forEach(System.out::println);
    }

    private List<Person> generatePersons(){
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("Tom", 8900, "male", "New York"));
        personList.add(new Person("Jack", 7000, "male", "Washington"));
        personList.add(new Person("Lily", 7800, "female", "Washington"));
        personList.add(new Person("Anni", 8200, "female", "New York"));
        personList.add(new Person("Owen", 9500, "male", "New York"));
        personList.add(new Person("Alisa", 7900, "female", "New York"));
        return personList;
    }
}
class Person {
    // 姓名
    private String name;
    // 薪资
    private int salary;
    // 年龄
    private int age;
    //性别
    private String sex;
    // 地区
    private String area;

    // 构造方法
    public Person(String name, int salary, String sex,String area) {
        this.name = name;
        this.salary = salary;
        this.sex = sex;
        this.area = area;
    }

    public Person(String name, int salary, int age, String sex, String area) {
        this.name = name;
        this.salary = salary;
        this.age = age;
        this.sex = sex;
        this.area = area;
    }

    // 省略了get和set，请自行添加

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getArea() {
        return area;
    }

    public void setArea(String area) {
        this.area = area;
    }



    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", salary=" + salary +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                ", area='" + area + '\'' +
                '}';
    }
}